﻿<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <style>
        .success {
            background-color: #4CAF50;
        }
    </style>
    <title>CORS Sample</title>
</head>
<body>
    <p>CORS Sample</p>
    <table>
        <thead>
            <tr>
                <th>Scenario</th>
                <th>Result</th>
            </tr>
        </thead>
        <tbody>
            <tr id="scenarios"></tr>
        </tbody>
    </table>
    <script type="text/javascript">
        (function () {
            function _fetch(options) {
                const url = `http://${location.hostname}:9000/${options.testPath}`;
                options.cors = 'cors';
                return fetch(url, options);
            }

            function assertSuccess(options) {
                return _fetch(options).then(s => true).catch(s => false);
            }

            function assertFailure(options) {
                return _fetch(options).then(s => false).catch(s => true);
            }

            const scenarios = {
                "Simple GET Request": assertSuccess({
                    testPath: 'allow-origin',
                    method: 'GET'
                }),

                "Simple PUT Request": assertSuccess({
                    testPath: 'allow-origin',
                    method: 'PUT'
                }),

                "Disallowed DELETE Method": assertFailure({
                    testPath: 'allow-header-method',
                    method: 'DELETE'
                }),

                "Allowed Header": assertSuccess({
                    testPath: 'allow-header-method',
                    method: 'PUT',
                    headers: new Headers({ "X-Test": "value", 'Content-Type': 'application/json' })
                }),

                // This one is weird - although the server performs a preflight request and receives a Access-Control-Allow-Methods: PUT,
                // the browser happily ignores the disallowed POST method
                "Allowed Header Disallowed POST": assertSuccess({
                    testPath: 'allow-header-method',
                    method: 'POST',
                    headers: new Headers({ "X-Test": "value", 'Content-Type': 'application/json' })
                }),

                "Disallowed Header": assertFailure({
                    testPath: 'allow-header-method',
                    method: 'POST',
                    headers: new Headers({ "Api-Key": "some_key", 'Content-Type': 'application/json' })
                }),

                "Disallowed Credentials": assertFailure({
                    testPath: 'allow-origin',
                    method: 'POST',
                    credentials: 'include'
                }),

                "Disallowed Credentials with preflight": assertFailure({
                    testPath: 'allow-origin',
                    method: 'PUT',
                    credentials: 'include'
                }),

                "Allowed Credentials": assertSuccess({
                    testPath: 'allow-credentials',
                    method: 'GET',
                    credentials: 'include'
                }),

                "Allowed Credentials with preflight": assertSuccess({
                    testPath: 'allow-credentials',
                    method: 'PUT',
                    credentials: 'include'
                }),

                "Disallowed exposed header": _fetch({
                    testPath: 'exposed-header',
                    method: 'GET'
                }).then(response => !response.headers.has("x-disallowedheader")),

                "Allowed exposed header": _fetch({
                    testPath: 'exposed-header',
                    method: 'GET'
                }).then(response => response.headers.has("x-allowedheader"))
            };

            const scenariosElement = document.querySelector('#scenarios');
            Object.keys(scenarios).map(scenario => {
                const row = document.createElement('tr');
                row.setAttribute("class", "scenario");
                scenariosElement.appendChild(row);

                let resultHtml = '<span class="waiting">⌛</span>';
                const setHtml = () => row.innerHTML = `<td>${scenario}</td><td>${resultHtml}</td>`;

                setHtml();

                return scenarios[scenario].then(result => {
                    resultHtml = result ?
                        '<span class="success">✓</span>' :
                        '<span class="failed">❌<span>';
                    setHtml();
                });
            });
        })();

    </script>

</body>
</html>
